﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Gauss.Isp
{
    public partial class TransitionNavigator : Form
    {
        private TreeView _treeView;
        private Thread _thread;
        private Transitions _transitions;
        private bool _stopThread;
        private Envelope _selectedEnvelope;
        private int _currentInterleaving;
        private Dictionary<Envelope, TreeNode> _treeNodes;

        public event EventHandler<EnvelopeClickedEventArgs> EnvelopeClicked;

        public class EnvelopeClickedEventArgs : EventArgs
        {
            private Envelope _envelope;

            public EnvelopeClickedEventArgs(Envelope envelope)
            {
                _envelope = envelope;
            }

            public Envelope Envelope
            {
                get { return _envelope; }
                set { _envelope = value; }
            }
        }

        public Envelope SelectedEnvelope
        {
            get
            {
                return _selectedEnvelope;
            }
            set
            {
                TreeNode node = null;
                lock (_treeNodes)
                {
                    if (_treeNodes.ContainsKey(value))
                        node = _treeNodes[value];
                }
                if (node != null)
                {
                    lock (_treeView)
                    {
                        _treeView.SelectedNode = node;
                    }
                }
                _selectedEnvelope = value;
            }
        }

        public int Interleaving
        {
            set { _currentInterleaving = value; }
        }

        public TransitionNavigator(Transitions transitions)
        {
            if (transitions == null)
                throw new ArgumentNullException("transitions");

            InitializeComponent();

            this.Load += new EventHandler(TransitionNavigator_Load);
            _transitions = transitions;
            _selectedEnvelope = null;
            _currentInterleaving = -1;
            _treeNodes = new Dictionary<Envelope, TreeNode>();
            
            // Construct the tree view object.
            _treeView = new TreeView();
            lock (_treeView)
            {
                _treeView.HideSelection = false;
                _treeView.Dock = DockStyle.Fill;
                _treeView.Nodes.Add("Loading...");
                this.Controls.Add(_treeView);
            }
        }

        private void TransitionNavigator_Load(object sender, EventArgs e)
        {
            // Populate the tree view in another thread, as it might take some time.
            _stopThread = false;
            _thread = new Thread(new ThreadStart(PopulateTreeView));
            _thread.Start();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            _stopThread = true;
            if (_thread != null && _thread.IsAlive)
                _thread.Join(int.MaxValue - 1);
        }

        private void PopulateTreeView()
        {
            // Construct the tree nodes.
            TreeNode selectedNode = null;
            TreeNode[] interleavings = null;
            lock (_transitions)
            {
                interleavings = new TreeNode[_transitions.TotalInterleavings];
                for (int i = 1; i <= _transitions.TotalInterleavings; i++)
                {
                    TreeNode interleaving = new TreeNode("Interleaving " + i);
                    if (i == _currentInterleaving)
                        interleaving.Expand();
                    interleavings[i - 1] = interleaving;
                    TreeNode[] ranks = new TreeNode[_transitions.Ranks];
                    for (int j = 0; j < _transitions.Ranks; j++)
                    {
                        ranks[j] = new TreeNode("Rank " + j);
                        interleaving.Nodes.Add(ranks[j]);
                        if (i == _currentInterleaving)
                            ranks[j].Expand();
                    }
                    foreach (Envelope e in _transitions.GetEnvelopesInInterleaving(i))
                    {
                        if (_stopThread) return;

                        TreeNode node = new TreeNode(Utils.StringFormat("{0}: {1}", e.Index, e.ToString()));
                        if (e.Assert)
                            node.Text = e.ToString();
                        if (e.IssueIndex < 0)
                        {
                            node.ForeColor = Color.Red;
                            lock (_treeView)
                            {
                                node.NodeFont = new Font(_treeView.Font, FontStyle.Bold);
                            }
                        }
                        node.Tag = e;
                        if (e == _selectedEnvelope)
                            selectedNode = node;
                        ranks[e.Rank].Nodes.Add(node);
                        lock (_treeNodes)
                        {
                            _treeNodes.Add(e, node);
                        }
                    }
                }
            }

            // Populate the tree.
            if (interleavings != null)
            {
                lock (_treeView)
                {
                    if (_treeView.InvokeRequired)
                    {
                        _treeView.Invoke(new MethodInvoker(
                            delegate()
                            {
                                _treeView.Nodes.Clear();
                                foreach (TreeNode tn in interleavings)
                                {
                                    _treeView.Nodes.Add(tn);
                                }
                                _treeView.DoubleClick += new EventHandler(TreeView_DoubleClick);
                                _treeView.SelectedNode = selectedNode;
                            }));
                    }
                    else
                    {
                        _treeView.Nodes.Clear();
                        foreach (TreeNode tn in interleavings)
                        {
                            _treeView.Nodes.Add(tn);
                        }
                        _treeView.DoubleClick += new EventHandler(TreeView_DoubleClick);
                        _treeView.SelectedNode = selectedNode;
                    }
                }
            }

        }

        private void TreeView_DoubleClick(object sender, EventArgs e)
        {
            TreeView tree = sender as TreeView;
            if (tree == null)
                return;

            Envelope env = tree.SelectedNode.Tag as Envelope;
            if (env == null)
                return;

            _selectedEnvelope = env;

            if (EnvelopeClicked != null)
            {
                EnvelopeClicked(this, new EnvelopeClickedEventArgs(env));
            }
        }
    }
}
